package vip.manda.framework.data.repository.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.hutool.db.Page;
import cn.hutool.db.PageResult;
import vip.manda.framework.data.DataBaseSource;
import vip.manda.framework.data.DataType;
import vip.manda.framework.data.repository.BaseRepository;
import vip.manda.framework.log.Log;
import vip.manda.framework.log.LogFactory;

import java.sql.SQLException;
import java.util.*;

/**
 * @author hongda.li 2022-04-12 20:45
 */
public abstract class BaseRepositoryImpl implements BaseRepository {

    private final Set<String> columns;
    private final String tableName;
    public final Log log = LogFactory.getLog(this.getClass());
    /**
     * 设置实体字段至列名的映射关系
     * @return 映射关系
     */
    public abstract Map<String, DataType> getColumns();

    public String getTableName(){
        return this.tableName;
    }
    public BaseRepositoryImpl() {
        this.tableName = StrUtil.toUnderlineCase(this.getClass().getSimpleName());
        this.columns = getColumns().keySet();
    }

    @Override
    public Db getDb() {
        return Db.use(DataBaseSource.getDataSource());
    }

    @Override
    public boolean insert(Entity entity) {
        log.info("SQL[{}]", "insert into " + tableName + " ?");
        log.info("Params[{}]", entity.toString());
        entity.setTableName(tableName);
        try {
            return Db.use(DataBaseSource.getDataSource()).insert(entity) != 0;
        } catch (SQLException e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public Long insertAndGetKey(Entity entity) {
        log.info("SQL[{}]", "insert into " + tableName + " ?");
        log.info("Params[{}]", entity.toString());
        entity.setTableName(tableName);
        try {
            return Db.use(DataBaseSource.getDataSource()).insertForGeneratedKey(entity);
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public boolean delete(Entity entity){
        log.info("SQL[{}]", "delete from " + tableName + " where ?");
        log.info("Params[{}]", entity.toString());
        entity.setTableName(tableName);
        try {
            return Db.use(DataBaseSource.getDataSource()).del(entity) != 0;
        } catch (SQLException e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public boolean delete(int id) {
        log.info("SQL[{}]", "delete from " + tableName + " where id=" + id);
        return delete(Entity.create().set("id", id));
    }

    @Override
    public boolean update(Entity entity, Entity where){
        log.info("SQL[{}]", "update " + tableName + "entity where ?");
        log.info("Params[{}][{}]", entity.toString(), where.toString());
        try {
            return Db.use(DataBaseSource.getDataSource()).update(entity, where) != 0;
        } catch (SQLException e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public boolean update(Entity entity, int id) {
        log.info("SQL[{}]", "update " + tableName + " ? where id=" + id);
        log.info("Params[{}]", entity.toString());
        return update(entity, Entity.create().set("id", id));
    }

    @Override
    public Map<String, Object> findOne(Entity entity){
        log.info("SQL[{}]","select from " + tableName + " where ?");
        log.info("Params[{}]", entity.toString());
        entity.setTableName(tableName);
        List<Entity> list;
        try {
            list = Db.use(DataBaseSource.getDataSource()).find(entity);
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
        if (list == null || list.isEmpty()){
            return null;
        }
        Entity result = list.get(0);
        Map<String, Object> data = new HashMap<>(columns.size());
        columns.forEach(column -> data.put(column, result.get(column)));
        return data;
    }

    @Override
    public Map<String, Object> findOne(int id) {
        log.info("SQL[{}]", "select * from " + tableName + " where id=" + id);
        return findOne(Entity.create().set("id", id));
    }

    @Override
    public List<Map<String, Object>> findAll(){
        log.info("SQL[{}]", "select * from " + tableName);
        List<Entity> list;
        try {
            list = Db.use(DataBaseSource.getDataSource()).findAll(tableName);
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
        if (list == null || list.isEmpty()){
            return null;
        }
        return parseResult(list);
    }

    @Override
    public List<Map<String, Object>> find(Entity entity){
        log.info("SQL[{}]","select from " + tableName + " where ?");
        log.info("Params[{}]", entity.toString());
        entity.setTableName(tableName);
        List<Entity> list;
        try {
            list = Db.use(DataBaseSource.getDataSource()).find(entity);
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
        if (list == null || list.isEmpty()){
            return null;
        }
        return parseResult(list);
    }

    @Override
    public List<Map<String, Object>> findPage(Entity entity, Page page){
        log.info("SQL[{}]","select from " + tableName + " where ?");
        log.info("Params[{}][{}]", entity.toString(), page.toString());
        entity.setTableName(tableName);
        PageResult<Entity> result;
        try {
            result = Db.use(DataBaseSource.getDataSource()).page(entity, page);
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
        if (result == null || result.isEmpty()){
            return null;
        }
        return parseResult(result);
    }

    @Override
    public List<Map<String, Object>> find(String sql, Object... params){
        log.info("SQL[{}]",sql);
        log.info("Params[{}]", params);
        List<Entity> list;
        try {
            list = Db.use(DataBaseSource.getDataSource()).query(sql, params);
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
        if (list == null || list.isEmpty()){
            return null;
        }
        return parseResult(list);
    }

    @Override
    public List<Map<String, Object>> find(Set<String> columns, String sql, Object... params) {
        List<Entity> result;
        try {
            result = Db.use(DataBaseSource.getDataSource()).query(sql, params);
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
        if (result == null || result.isEmpty()){
            return null;
        }
        List<Map<String, Object>> dataList = new ArrayList<>(result.size());
        for (Entity entity : result) {
            Map<String, Object> data = new HashMap<>(columns.size());
            columns.forEach(column -> data.put(column, entity.get(column)));
            dataList.add(data);
        }
        return dataList;
    }

    private List<Map<String, Object>> parseResult(List<Entity> result){
        List<Map<String, Object>> dataList = new ArrayList<>(result.size());
        for (Entity temp : result) {
            Map<String, Object> data = new HashMap<>(columns.size());
            columns.forEach(column -> data.put(column, temp.get(column)));
            dataList.add(data);
        }
        return dataList;
    }
}
